import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.ImageIcon;
import javax.swing.JLabel;

/**
 * 扑克牌类，表示一张可交互的扑克牌
 * 所需要的功能:
 *   1.显示扑克牌的正反面
 *   2.响应鼠标点击事件
 *   3.支持选中/取消选中状态
 *   4.提供卡牌移动动画效果
 *   5.管理卡牌状态（是否可点击、是否已选中）
 */
public class Card extends JLabel implements MouseListener {
    // 卡牌状态常量
    private static final int SELECTED_OFFSET = 20; // 选中状态偏移量
    private static final int ANIMATION_DELAY = 5; // 动画帧延迟（毫秒）
    
    private GameMain game;   // 主游戏引用
    private String cardName; // 卡牌标识（格式："花色-点数"，如"1-13"表示黑桃K）
    private boolean faceUp;  // 是否正面朝上
    private boolean clickable; // 是否可点击
    private boolean selected;   // 是否已选中

    /**
     * 卡牌构造函数
     * 
     * @param game 游戏主类引用
     * @param cardName 卡牌标识（格式："花色-点数"）
     * @param faceUp 初始方向
     */
    public Card(GameMain game, String cardName, boolean faceUp) {
        this.game = game;
        this.cardName = cardName;
        this.faceUp = faceUp;
        
        // 设置初始状态
        setCardFace(faceUp);
        setSize(71, 96); // 标准扑克牌尺寸
        setVisible(true);
        addMouseListener(this); // 注册鼠标监听器
    }

    /**
     * 设置卡牌显示面（正面或背面）
     * 
     * @param front true显示正面，false显示背面
     */
    public void setCardFace(boolean front) {
        if (front) {
            setIcon(new ImageIcon("images/" + cardName + ".gif"));
        } else {
            setIcon(new ImageIcon("images/rear.gif"));
        }
        this.faceUp = front;
    }

    /**
     * 鼠标点击事件处理
     * 
     * <p>当卡牌可点击时，先获得位置后决定相应的播放动画
     */
    @Override
    public void mouseClicked(MouseEvent e) {
        if (clickable) {
            Point currentLocation = getLocation();
            int offset = selected ? SELECTED_OFFSET : -SELECTED_OFFSET;
            
            // 计算新位置（选中上移，取消选中下移）
            Point newLocation = new Point(
                currentLocation.x, 
                currentLocation.y + offset
            );
            
            // 播放动画效果
            animateMove(currentLocation, newLocation);
            
			// 更新选中状态
            selected = !selected;
        }
    }

    /**
     * 播放卡牌移动动画
     * 
     * @param from 起始位置
     * @param to 目标位置
     */
    private void animateMove(Point from, Point to) {
        // 计算移动轨迹的线性方程参数
        double slope = (double)(to.y - from.y) / (to.x - from.x);
        double intercept = to.y - to.x * slope;
        
        // 确定移动方向（左/右）
        int step = from.x < to.x ? 1 : -1;
        
        // 逐帧移动
        for (int x = from.x; Math.abs(x - to.x) > 1; x += step) {
            int y = (int)(slope * x + intercept);
            setLocation(x, y);
            
            // 添加动画延迟
            try {
                Thread.sleep(ANIMATION_DELAY);
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
        
        // 最终定位到目标位置
        setLocation(to);
    }

    // 其他MouseListener方法（未使用但必须实现）
    @Override public void mouseEntered(MouseEvent e) {}  // 鼠标进入
    @Override public void mouseExited(MouseEvent e) {}   // 鼠标离开
    @Override public void mousePressed(MouseEvent e) {}  // 鼠标按下
    @Override public void mouseReleased(MouseEvent e) {} // 鼠标释放

    // -------------------- Getter/Setter方法 --------------------
    
    /**
     * 获取卡牌标识
     * @return 卡牌标识（格式："花色-点数"）
     */
    public String getCardName() { 
        return cardName; 
    }
    
    /**
     * 判断是否正面朝上
     * @return true=正面朝上，false=背面朝上
     */
    public boolean isFaceUp() { 
        return faceUp; 
    }
    
    /**
     * 判断是否可点击
     * @return true=可点击，false=不可点击
     */
    public boolean isClickable() { 
        return clickable; 
    }
    
    /**
     * 判断是否已选中
     * @return true=已选中，false=未选中
     */
    public boolean isSelected() { 
        return selected; 
    }
    
    /**
     * 设置卡牌可点击状态
     * @param clickable true=可点击，false=不可点击
     */
    public void setClickable(boolean clickable) { 
        this.clickable = clickable; 
        
        // 重置选中状态
        if (!clickable && selected) {
            Point current = getLocation();
            setLocation(current.x, current.y + SELECTED_OFFSET);
            selected = false;
        }
    }
    
    /**
     * 设置卡牌选中状态
     * @param selected true=选中，false=取消选中
     */
    public void setSelected(boolean selected) {
        if (this.selected != selected) {
            // 模拟点击效果
            mouseClicked(null);
        }
    }
    
    /**
     * 翻转卡牌（正面变背面，背面变正面）
     */
    public void flip() {
        setCardFace(!faceUp);
    }
    
    /**
     * 显示卡牌正面
     */
    public void showFront() {
        if (!faceUp) setCardFace(true);
    }
    
    /**
     * 显示卡牌背面
     */
    public void showBack() {
        if (faceUp) setCardFace(false);
    }
    
    /**
     * 解析花色值
     * @return 花色数值（1=黑桃, 2=红心, 3=梅花, 4=方块, 5=王）
     */
    public int getSuitValue() {
        return Integer.parseInt(cardName.split("-")[0]);
    }
    
    /**
     * 解析点数值
     * @return 点数数值（3-10, J=11, Q=12, K=13, A=1, 2=2, 小王=14, 大王=15）
     */
    public int getRankValue() {
        return Integer.parseInt(cardName.split("-")[1]);
    }
    
    /**
     * 获取卡牌花色名称
     * @return 花色名称（黑桃、红桃等）
     */
    public String getSuitName() {
        switch (getSuitValue()) {
            case 1: return "黑桃";
            case 2: return "红心";
            case 3: return "梅花";
            case 4: return "方块";
            case 5: return (getRankValue() == 14) ? "小王" : "大王";
            default: return "未知";
        }
    }
    
    /**
     * 获取卡牌点数名称
     * @return 点数名称（A、2、3...K）
     */
    public String getRankName() {
        int rank = getRankValue();
        if (rank >= 3 && rank <= 10) return String.valueOf(rank);
        switch (rank) {
            case 1: return "A";
            case 2: return "2";
            case 11: return "J";
            case 12: return "Q";
            case 13: return "K";
            case 14: return "小王";
            case 15: return "大王";
            default: return "未知";
        }
    }
    
    /**
     * 获取卡牌完整名称
     * @return 完整名称（如"黑桃A"）
     */
    public String getFullName() {
        return getSuitName() + getRankName();
    }
}